/*
 * Copyright (C) 2006 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package servlets;

import util.RequestUtil;
import util.SamlException;
import util.Util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * This servlet, part of the SAML-based Single Sign-On Reference Tool, generates
 * a SAML request and then forwards the request to the Identity Provider.
 * <p>
 * <ul>
 * SAML parameters:
 * <p>
 * <li> URI for the Identity Provider's single sign-on service </li>
 * <li> Service Provider's name </li>
 * <li> Relay state URL (end goal URL) </li>
 * <li> Assertion Consumer Service URL </li>
 * <ul>
 * 
 */
public class CreateRequestServlet extends HttpServlet {

  private static final String AUTHN_REQUEST_TEMPLATE = 
    "AuthnRequestTemplate.xml";

  /*
   * Generates a SAML AuthnRequest XML by replacing the specified ACS URL and
   * provider name in the SAML AuthnRequest template file. Returns the string
   * format of the XML file.
   */
  private String createAuthnRequest(String acsURL, String providerName)
      throws SamlException {
    String filepath = getServletContext().getRealPath(
      "templates/" + AUTHN_REQUEST_TEMPLATE);
    String authnRequest = Util.readFileContents(filepath);
    authnRequest = authnRequest.replace("<PROVIDER_NAME>", providerName);
    authnRequest = authnRequest.replace("<ACS_URL>", acsURL);
    authnRequest = authnRequest.replace("<AUTHN_ID>", Util.createID());
    authnRequest = authnRequest.replace("<ISSUE_INSTANT>", Util
      .getDateAndTime());
    return authnRequest;
  }

  /*
   * Generates the URL to forward the SAML AuthnRequest to the Identity
   * Provider's single sign-on service.
   */
  private String computeURL(String ssoURL, String authnRequest,
      String relayStateURL) throws SamlException {
    StringBuffer buf = new StringBuffer();
    try {
      buf.append(ssoURL);

      buf.append("?SAMLRequest=");
      buf.append(RequestUtil.encodeMessage(authnRequest));

      buf.append("&RelayState=");
      buf.append(URLEncoder.encode(relayStateURL, "UTF-8"));
      return buf.toString();
    } catch (UnsupportedEncodingException e) {
      throw new SamlException(
        "Error encoding SAML Request into URL: Check encoding scheme - "
          + e.getMessage());
    } catch (IOException e) {
      throw new SamlException(
        "Error encoding SAML Request into URL: Check encoding scheme - "
          + e.getMessage());
    }
  }

  /**
   * The doPost method handles HTTP POST requests sent to the
   * CreateRequestServlet. It reads in SAML parameters from request and generate
   * SAML AuthnRequest to forward to the Identity Provider.
   */
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    String action = request.getParameter("action");
    String returnPage = request.getParameter("returnPage");

    // Redirect to servlet at Identity Provider's end to parse AuthnReqest
    // parameters generated by this servlet.
    String ssoURL = "./ProcessResponseServlet";

    // Set the paramaters for AuthnRequest
    String providerName = "google.com";
    String domainName = "psosamldemo.net";
    String relayStateURL = "http://mail.google.com/a/" + domainName;
    String acsURI = "https://www.google.com/a/" + domainName + "/acs";

    String authnRequest;
    String redirectURL;
    try {
      // Create the AuthnRequest XML from above parameters
      authnRequest = createAuthnRequest(acsURI, providerName);
      request.setAttribute("authnRequest", authnRequest);
      // Compute URL to forward AuthnRequest to the Identity Provider
      redirectURL = computeURL(ssoURL, authnRequest, relayStateURL);
      request.setAttribute("redirectURL", redirectURL);

    } catch (SamlException e) {
      request.setAttribute("error", e.getMessage());
    }
    // Else, return generated AuthnRequest for display at Service Provider
    request.getRequestDispatcher(returnPage).include(request, response);
  }

}